import sklearn
import torch
from sklearn.metrics import confusion_matrix
# from utils.hsdf.hausdorff import hausdorff_distance
from scipy.spatial.distance import directed_hausdorff
# import surface-distance
import cv2
import torch.nn.functional as F
import numpy as np
from scipy import spatial


def threshold(image):
    # t = filters.threshold_otsu(image, nbins=256)
    image[image >= 127] = 255
    image[image < 127] = 0
    return image


def numeric_score(pred, gt):
    FP = np.float(np.sum((pred == 255) & (gt == 0)))
    FN = np.float(np.sum((pred == 0) & (gt == 255)))
    TP = np.float(np.sum((pred == 255) & (gt == 255)))
    TN = np.float(np.sum((pred == 0) & (gt == 0)))
    return FP, FN, TP, TN


def metrics_nerve(pred, label, batch_size):
    # pred = torch.argmax(pred, dim=1) # for CE Loss series
    outputs = (pred.data.cpu().numpy() * 255).astype(np.uint8)
    labels = (label.data.cpu().numpy() * 255).astype(np.uint8)
    # outputs = outputs.squeeze(1)  # for MSELoss()  #  7/06下午注释
    # labels = labels.squeeze(1)  # for MSELoss()
    # outputs = threshold(outputs)  # for MSELoss()在二值化之前都是概率值???

    Sen, BAcc, Fdr, Dice = 0., 0., 0., 0.
    for i in range(batch_size):
        output = outputs[i, :, :]
        gt = labels[i, :, :]

        # hasdff_dis = hausdorff_distance(output1, gt1) #,distance='cosine')
        # print(hasdff_dis)
        sen, fdr, dice = get_nerve(output, gt)
        # bacc = balanced_accuracy_score(gt, img)
        # print("acc, sen, fdr, dice",acc, sen, fdr, dice)
        Sen += sen
        # BAcc += bacc
        Fdr += fdr
        Dice += dice
        # Distance += hasdff_dis

    return Sen / batch_size, Fdr / batch_size, Dice / batch_size


def metrics_cell(pred, label, batch_size):
    # print("img.shape", label.shape)
    # print("gt.shape", pred.shape)
    # pred = torch.argmax(pred, dim=1) # for CE Loss series
    pred = (pred.data.cpu().numpy() * 255).astype(np.uint8)
    label = (label.data.cpu().numpy() * 255).astype(np.uint8)

    # outputs = (pred.data.numpy() * 255).astype(np.uint8)
    # labels = (label.data.numpy() * 255).astype(np.uint8)
    # pred = pred.squeeze(1)  # for MSELoss()
    # label = label.squeeze(1)  # for MSELoss()     ####### ?????????? 7/06下午注释
    # outputs = threshold(outputs)  # for MSELoss()在二值化之前都是概率值

    Sen, Spe, Dice = 0., 0., 0.
    for i in range(batch_size):
        output = pred[i, :, :]
        gt = label[i, :, :]
        # hasdff_dis = hausdorff_distance(output, gt)
        sen, spe, dice = get_cell(output, gt)
        # gt_tensor = torch.from_numpy(gt)
        # gt = gt_tensor.unsqueeze(2)
        # # print("gt.shape", gt.shape)
        # gt = gt.numpy()

        Sen += sen
        Spe += spe
        # BAcc += bacc
        Dice += dice
        # Distance += hasdff_dis
    return Sen / batch_size, Spe / batch_size, Dice / batch_size


def metrics_jaccard(pred, label):
    pred = (pred.data.cpu().numpy() * 255).astype(np.uint8)
    label = (label.data.cpu().numpy() * 255).astype(np.uint8)
    pred = pred.flatten()
    label = label.flatten()
    pred = threshold(pred)
    # test_auc = sklearn.metrics.roc_auc_score(label, pred)
    jaccard_ = (1 - spatial.distance.jaccard(pred, label))  ## * 100.0  ## 下方main中已测试，一组图片0.80左右还不错！！
    return jaccard_


def metrics_auc(pred, label):
    pred = pred.data.cpu().numpy()
    label = label.data.cpu().numpy()
    pred = pred.flatten()
    label = label.flatten()
    # test_auc = sklearn.metrics.roc_auc_score(label, pred, multi_class='ovo')   # 用于多分类：multi_class='ovo'
    test_auc = sklearn.metrics.roc_auc_score(label, pred)  # 用于多分类：multi_class='ovo'
    # jaccard_ = (1 - spatial.distance.jaccard(pred, label))  * 100.0  ## 下方main中已测试，一组图片0.80左右还不错！！
    return test_auc


def metrics_jaccard_batch(pred, label, batch_size):
    # pred = pred.data.cpu().numpy()
    # label = label.data.cpu().numpy()
    preds = (pred.data.cpu().numpy() * 255).astype(np.uint8)
    labels = (label.data.cpu().numpy() * 255).astype(np.uint8)

    # preds = pred.squeeze(1)
    # labels = label.squeeze(1)   ## 7/06下午注释
    Jaccard = 0.
    for i in range(batch_size):
        # print("pred.shape", pred.shape)
        pred = preds[i, :,
               :]  ### ?????why IndexError: too many indices for array: array is 1-dimensional, but 3 were indexed
        # # print("pred.shape", pred.shape)  ### 前后变量名要改，不能重复
        label = labels[i, :, :]
        pred = pred.flatten()
        label = label.flatten()
        # test_auc = sklearn.metrics.roc_auc_score(label, pred)
        # Auc += test_auc
        pred = threshold(pred)  ### 阈值化
        jaccard_ = (1 - spatial.distance.jaccard(pred, label)) * 100.0  ## 下方main中已测试，一组图片0.80左右还不错！！
        Jaccard += jaccard_
    return Jaccard / batch_size


def metrics_auc_batch(pred, label, batch_size):
    # pred = pred.data.cpu().numpy()
    # label = label.data.cpu().numpy()
    preds = (pred.data.cpu().numpy() * 255).astype(np.uint8)
    labels = (label.data.cpu().numpy() * 255).astype(np.uint8)

    # preds = pred.squeeze(1)
    # labels = label.squeeze(1)
    Auc = 0.
    for i in range(batch_size):
        # print("pred.shape", pred.shape)
        pred = preds[i, :,
               :]  ### ?????why IndexError: too many indices for array: array is 1-dimensional, but 3 were indexed
        # # print("pred.shape", pred.shape)  ### 前后变量名要改，不能重复
        label = labels[i, :, :]
        pred = pred.flatten()
        label = label.flatten()
        test_auc = sklearn.metrics.roc_auc_score(label, pred)
        Auc += test_auc
    # jaccard_ = (1 - spatial.distance.jaccard(pred, label))  * 100.0  ## 下方main中已测试，一组图片0.80左右还不错！！
    return Auc / batch_size


def get_nerve(image, label):
    image = threshold(image)
    FP, FN, TP, TN = numeric_score(image, label)
    sen = (TP) / (TP + FN + 1e-10)
    # spe = (TN) / (TN + FP + 1e-10)
    fdr = (FP) / (FP + TP + 1e-10)
    dice = 2 * TP / (FP + 2 * TP + FN + 1e-10)
    return sen, fdr, dice


def get_cell(output, label):
    # print("output.unique",np.unique(output))
    # print("label.unique:",np.unique(label))
    out = threshold(output)
    FP, FN, TP, TN = numeric_score(out, label)
    sen = (TP) / (TP + FN + 1e-10)
    spe = (TN) / (TN + FP + 1e-10)
    dice = 2 * TP / (FP + 2 * TP + FN + 1e-10)
    return sen, spe, dice


def HD_95(pred, label, batch_size):
    outputs = (pred.data.cpu().numpy() * 255).astype(np.uint8)
    labels = (label.data.cpu().numpy() * 255).astype(np.uint8)
    outputs = outputs.squeeze(1)  # for MSELoss()
    labels = labels.squeeze(1)  # for MSELoss()

    # outputs = threshold(outputs)  # for MSELoss()在二值化之前都是概率值???
    HD = 0.
    for i in range(batch_size):
        pred = outputs[i, :, :]
        label = labels[i, :, :]
        pred = pred.astype(bool)
        label = label.astype(bool)
        u = (400 * 400) / (384 * 384)  # 4.852578076171419体素间距
        dist1 = directed_hausdorff(pred, label)[0]
        dist2 = directed_hausdorff(label, pred)[0]
        hasdff_dis = max(dist1, dist2) * u
        # print(hasdff_dis)
        HD += hasdff_dis
    return HD / batch_size


###法二 ： deepmind的表面距离包https://github.com/deepmind/surface-distance
# HD = 0.
# for i in range(batch_size):
#     pred = outputs[i, :, :]
#     label = labels[i, :, :]
#     # spacing = pred.GetSpacing()
#     pred = pred.astype(bool)
#     label = label.astype(bool)
#     surf_dis = compute_surface_distances(label,pred, spacing_mm=(0.001, 0.001))#神经384pxel 对应400um（微米），转换为mm毫米就是0.001，但是算出来是0.15，上面的scipy库结果是20多
#
#     hd = compute_robust_hausdorff(surf_dis, 95)
#     print("hd", hd)
#     HD += hd
# return HD / batch_size


if __name__ == '__main__':
    # pred = cv2.imread("/home/jiayu/MyProject_2022/result/Pred/624_/Pred_c/FJ(92).png",flags=-1)
    # pred = pred.astype(bool)
    # print(pred.shape)
    # label = cv2.imread('/home/jiayu/Desktop/JiaYu_data/1219(分六组)/601-1219(select317)/134第一轮/1+1_134_DataSet/test/gt_cell/FJ(92).png', flags=-1)
    # label = label.astype(bool)
    #
    #
    # u = (400*400)/(384*384)   #4.852578076171419
    # dist1 = directed_hausdorff(pred, label)[0]
    # dist2 = directed_hausdorff(label, pred)[0]
    # hasdff_dis = max(dist1,dist2)
    #
    # print(hasdff_dis*u)
    pred = cv2.imread("/home/jiayu/MyProject_2022/result/Pred/624_/Pred_c/FJ(92).png", flags=0)
    label = cv2.imread(
        '/home/jiayu/Desktop/JiaYu_data/1219(分六组)/601-1219(select317)/134第一轮/1+1_134_DataSet/test/gt_cell/FJ(92).png',
        flags=0)
    print(pred.shape)
    print(label.shape)
    # pred = pred.astype(bool)
    # # print(dtype(pred))
    # label = label.astype(bool)
    # label = label / 255
    # pred = pred /255
    # label = label.flatten()
    # pred = pred.flatten()
    # jaccard1 = sklearn.metrics.jaccard_score(label, pred)   ### 0.8054509195656991
    jaccard = metrics_auc_jaccard(pred, label)
    print("jaccard", jaccard)
    # auc = metrics_auc_batch(pred,label)
    # print("auc-batch",auc)
    # label = label/255
    # label = label.astype(np.int64)
    # label = torch.from_numpy(label)
    #
    # # print("label", label.shape)
    # gt = F.one_hot(label, 2)   ##argmax gt.shape: torch.Size([384, 384, 2])
    # print("gt.shape", gt.shape)
    # gt = gt.numpy()

    # print("gt11.shape", gt.shaflags=-1pe)

    # pred = pred.astype(np.int64)
    # pred = torch.from_numpy(pred).numpy()
    # print("pred.unique", pred.unique())
    # pred[pred>0] = 1
    # pred = pred.astype(np.uint16)
    # # print("pred.unique", pred.unique())
    # # pred = torch.argmax(pred, dim=1)
    # print(pred.shape, pred.min(), pred.max(), pred.dtype)
    # aji = agg_jc_index(gt, pred)
    # print("aji", aji)

    print()
